<?php

/*
 * Tomato Framework
 *
 * Copyright 2012-2012 Luax.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @link http://www.tomatoframework.com
 * @link http://www.luaxlou.com
 * @version $Id$
 */

/**
 * Description of Cli
 *
 * @author luax
 */
class Cli {

    public static $cli;

    /**
     *
     * @var Smarty
     */
    private $smarty;
    private $templates = array(
        'resource' => array(
            array(
                'path' => '/resource/{resourceName|u}Resource.class.php',
                'tpl' => 'resource.class.tpl'
            )
        ),
        'service' => array(
            array(
                'path' => '/service/{resourceName|u}Service.class.php',
                'tpl' => 'service.class.tpl'
            )
        ),
        'dao' => array(
            array(
                'path' => '/dao/{resourceName|u}Dao.class.php',
                'tpl' => 'dao.class.tpl'
            )
        ),
        'template' => array(
            array(
                'path' => '/template/{resourceName}/',
                'tpl' => ''
            ),
            array(
                'path' => '/template/{resourceName}/_form.html',
                'tpl' => '_form.html'
            ),
            array(
                'path' => '/template/{resourceName}/create.html',
                'tpl' => 'create.html'
            ),
            array(
                'path' => '/template/{resourceName}/edit.html',
                'tpl' => 'edit.html'
            ),
            array(
                'path' => '/template/{resourceName}/list.html',
                'tpl' => 'list.html'
            ),
            array(
                'path' => '/template/{resourceName}/show.html',
                'tpl' => 'show.html'
            ),
        ),
    );
    private $applications = array();

    public function __construct() {
        $this->smarty = SmartyAdapter::instance();

        $this->smarty->left_delimiter = "<~";
        $this->smarty->right_delimiter = "~>";
    }

    public static function run($args) {

        $command = $args[0];

        $params = array_slice($args, 1);

        $cli = new Cli();

        return $cli->$command($params);
    }

    public function create() {
        echo "Warnning!!!\nOperation will override all the app resources and tables,are you sure?[y/n]";

        fscanf(STDIN, "%s\n", $s);

        if ($s != 'y') {
            return;
        }

        $this->_parseConfig();

        $this->_createResources();
    }

    private function _parseConfig() {
        $applications = $this->_loadSchema(new SimpleXMLElement(file_get_contents(APPLICATION_PATH . '/schema.xml')));
        foreach ($applications as $application) {
            $applicationName = $application['name'];

            foreach ($application['children'] as $resource) {
                $resourceName = $resource['name'];

                $applications[$applicationName]['children'][$resourceName]['refs'] = array();
                
                $applications[$applicationName]['children'][$resourceName]['autoupdates'] = array();
                $applications[$applicationName]['children'][$resourceName]['autocreates'] = array();

                foreach ($resource['children'] as $column) {
                    $columnName = $column['name'];

                    if (isset($column['ref'])) {
                        $refResource = &$applications[$applicationName]['children'][$column['ref']];
                        $applications[$applicationName]['children'][$resourceName]['refs'][$columnName] = $refResource;
                    }
                    
                    if (isset($column['autoupdate'])) {
            
                        $applications[$applicationName]['children'][$resourceName]['autoupdates'][$columnName] = $column['autoupdate'];
                    }
                    
                    if (isset($column['autocreate'])) {
            
                        $applications[$applicationName]['children'][$resourceName]['autocreates'][$columnName] = $column['autocreate'];
                    }
                }
            }
        }

        $this->applications = $applications;
    }

    private function _loadSchema($xml) {

        $result = array();

        foreach ($xml->children() as $child) {

            $array = (Array) $child;

            $t = $array["@attributes"];
            $childArray = (Array) $child->children();

            if (sizeof($childArray) > 0) {

                $t['children'] = $this->_loadSchema($child);
            }
            $result[$t['name']] = $t;
        }
        return $result;
    }

    private function _createResources() {

        foreach ($this->applications as $application) {

            if ($application['generate'] !== '1') {
                return;
            }
            echo "application {$application['name']}[{$application['apppath']}]:\n";
            echo "creating resources...\n";

            $this->smarty->assign('resources', $application['children']);

            $menu = $this->smarty->fetch("menu.html");

            $targetPath = $application['apppath'] . '/template/menu.html';
            file_put_contents($targetPath, $menu);

            echo "created file {$targetPath}\n";

            foreach ($application['children'] as $resource) {

                $this->_createResource($resource, $application);

                $this->createTable($resource);
            }
        }
    }

    private function createTable($resource) {

        $tableName = $resource['tablename'];
        $pk = $resource['pk'];

        echo "create table {$tableName}";

        $sth = Load::db()->prepare("drop table if exists {$tableName};");

        $sth->execute();


        $fields = array();

        foreach ($resource['children'] as $column) {
            $columnName = $column['name'];
            $autoIncrement = "";

            if ($columnName == $pk) {
                $autoIncrement = ' AUTO_INCREMENT';
            }

            $fields[] = "{$column['name']} {$column['type']} {$autoIncrement}";
        }

        $refs = $resource['refs'];
        
        $arr = array();

        $refString = "";
        if (sizeof($refs) > 0) {
            foreach ($refs as $k=> $ref) {
                $arr[] = "CONSTRAINT fk_{$tableName}_{$k} FOREIGN KEY ({$k}) REFERENCES {$ref['tablename']}({$ref['pk']})";
            }

            $refString = ',' . implode(",", $arr);
        }


        $fieldsString = implode(",", $fields);

        $sql = "CREATE TABLE {$tableName}(
                    $fieldsString,
                    PRIMARY KEY ({$pk})
                    $refString
            ) ;";
        $sth = Load::db()->prepare($sql);



        $result = $sth->execute();
        if ($result) {
            echo " successful.\n";
        } else {
            echo " fail.\n"; 
            var_dump($sth->errorInfo());
        }
    }

    private function _createResource($resource, $application) {


        $columns = $resource['children'];

        $resourceName = $resource['name'];
        $tableName = $resource['tablename'];

        $pk = $resource['pk'];



        $modifyControls = $this->parseModifyControls($columns, $resourceName, $resource['modifyfields']);

        echo "creating resource {$tableName}...\n";

        foreach ($this->templates as $array) {

            foreach ($array as $template) {

                $targetPath = str_replace('{resourceName|u}', ucfirst($resourceName), $template['path']);
                $targetPath = str_replace('{resourceName}', $resourceName, $targetPath);

                $targetPath = $application['apppath'] . $targetPath;

                if (empty($template['tpl'])) {
                    @mkdir($targetPath, 0777, true);
                    continue;
                }

                $this->smarty->assign(array(
                    'applicationName' => $application['name'],
                    'caption' => $resource['caption'],
                    'resourceName' => $resourceName,
                    'tableName' => $tableName,
                    'columns' => $columns,
                    'modifyControls' => $modifyControls,
                    'pk' => $pk,
                    's_modifyFields' => $resource['modifyfields'],
                    's_showFields' => $resource['showfields'],
                    's_listFields' => $resource['listfields'],
                    'modifyFields' => explode(',', $resource['modifyfields']),
                    'showFields' => explode(',', $resource['showfields']),
                    'listFields' => explode(',', $resource['listfields']),
                    'autoCreates' => $resource['autocreates'],
                    'autoCreateKeys' => array_keys($resource['autocreates']),
                    'autoCreateValues' => array_values($resource['autocreates']),
                    'autoUpdates' =>  $resource['autoupdates']
                ));
                $code = $this->smarty->fetch($template['tpl']);

                file_put_contents($targetPath, $code);
                echo "created file {$targetPath}\n";
            }
        }
    }

    public function parseModifyControls($columns, $resourceName, $modifyFields) {

        $modifyFieldArray = explode(',', $modifyFields);

        $inputTemplate = '<input name="%s" type="text" id="%s" class="%s" placeholder="%s" value="{$%s.%s}" />';
        $textareaTemplate = '<textarea name="%s" id="%s" class="%s" placeholder="%s" rows="%s">{$%s.%s}</textarea>';


        $selectTemplate = '<select name="%s" id="%s" class="%s" placeholder="%s">';
        $selectTemplate = '{foreach form="%s_refs" item="row"}<option name="{$row.%s}">{$row.%s}</option>{/foreach}';
        $selectTemplate = ' </select>';


        foreach ($columns as $key => $col) {

            $field = $col['name'];
            $type = $col['type'];

            if (!in_array($field, $modifyFieldArray)) {
                unset($columns[$key]);
                continue;
            }

            $matches;

            if (preg_match("/varchar\((\d+)\)/", $type, $matches)) {



                if ($matches[1] < 255) {
                    $columns[$key]['input'] = sprintf($inputTemplate, $field, $field, "input-xxlarge", $field, $resourceName, $field);
                } else {
                    $columns[$key]['input'] = sprintf($textareaTemplate, $field, $field, "input-xxlarge", $field, "", $resourceName, $field);
                }
            } elseif ($type == 'text') {
                $columns[$key]['input'] = sprintf($textareaTemplate, $field, $field, "input-xxlarge", $field, 10, $resourceName, $field);
            } else {


                $columns[$key]['input'] = sprintf($inputTemplate, $field, $field, "", $field, $resourceName, $field);
            }
        }



        return $columns;
    }

}